package com.bauer.base.lock;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import sun.misc.Unsafe;

/**
 * @description:
 * @author: weirui
 * @create: 2022-07-05 12:29
 **/
public class SimpleLock {

    private static int counter = 0;

    private int lock = 0;
    private static Unsafe unsafe;
    private static BlockingQueue<Thread> blockQueue = new LinkedBlockingQueue<>(10);
    private static ConcurrentMap<String, Integer> threadName = new ConcurrentHashMap<>();

    public static Unsafe geyUnsafeInstance() throws Exception {
        Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeInstance.setAccessible(true);
        return (Unsafe) theUnsafeInstance.get(Unsafe.class);
    }

    public void lock() throws Exception {

        while (!unsafe
            .compareAndSwapInt(this, unsafe.objectFieldOffset(SimpleLock.class.getDeclaredField("lock")), 0, 1)) {
            Thread current = Thread.currentThread();
            blockQueue.put(current);
            System.out.println("park before :" + current.getName());
            unsafe.park(false, 0L);
            System.out.println("park after :" + current.getName());
        }
    }

    public void unlock() {
        lock = 0;
        Thread thread = blockQueue.poll();
        if (thread != null) {
            System.out.println("unlock  :" + thread.getName());
            unsafe.unpark(thread);
        }
    }

    public static void main(String[] args) throws Exception {
        unsafe = geyUnsafeInstance();
        SimpleLock simpleLock = new SimpleLock();
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 2; i++) {
            executorService.execute(new Counter(simpleLock));
        }

    }

    static class Counter implements Runnable {

        private SimpleLock simpleLock;

        public Counter(SimpleLock simpleLock) {
            this.simpleLock = simpleLock;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                try {
                    simpleLock.lock();
                    counter++;
                } catch (Exception exception) {
                    exception.printStackTrace();
                } finally {
                    simpleLock.unlock();
                }

            }
            System.out.println(counter);
        }
    }
}
